﻿#include "HalconModelMatchWidget.h"
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QLabel>
#include <QApplication>
#include "ImageCommon.h"
#pragma execution_character_set("utf-8")

HalconModelMatchWidget::HalconModelMatchWidget(QWidget *parent)
    : QWidget{parent}
{
    HalconCpp::SetSystem("clip_region","false");
    setupUI();
    initUI();
    initConnection();
}

void HalconModelMatchWidget::setImage(const QImage &img)
{
    mImg = img;
    wgtRoiModelCreate->setImage(mImg);
    wgtRoiModelFind->setImage(mImg);
}

ShapeMatchParam HalconModelMatchWidget::getParam()
{
    updateModelCreatePar();
    updateModelFindPar();
    return mParam;
}

void HalconModelMatchWidget::setParam(const ShapeMatchParam &par)
{
    try {
        mParam = par;
        spboxNumLevels->setValue(mParam.createParam.numLevels.I());
        spboxAngleStart->setValue(mParam.createParam.angleStart.D());
        dspboxAngleStep->setValue(mParam.createParam.angleStep.D());
        spboxContrastMin->setValue(mParam.createParam.contrastMin.I());
        spboxCenterPosRow->setValue(mParam.createParam.centerPosRow.I());
        spboxCenterPosCol->setValue(mParam.createParam.centerPosCol.I());
        cbboxMetric->setCurrentText(mParam.createParam.metric.S().ToLocal8bit());

        spboxContrastLow->setValue(mParam.createParam.contrast[0].I());
        spboxContrastHigh->setValue(mParam.createParam.contrast[1].I());
        spboxPieceSizeMin->setValue(mParam.createParam.contrast[2].I());

        cbboxOptimization->setCurrentText(mParam.createParam.optimization[0].S().ToLocal8bit());
        cbboxCreateShape->setCurrentText(mParam.createParam.optimization[1].S().ToLocal8bit());

        spboxNumToFind->setValue(mParam.findParam.numToFind.I());
        dspboxMinScore->setValue(mParam.findParam.minScore.D());
        dspboxMaxOverlap->setValue(mParam.findParam.maxOverlap);
        cbboxSubPixel->setCurrentText(mParam.findParam.subPixel.S().ToLocal8bit());
        dspboxGreedness->setValue(mParam.findParam.greediness.D());

        spboxNumLevelMin->setValue(mParam.findParam.numLevels[1].I());


        ItemBase* itemCreate;
        if(mParam.createParam.roiType == DIT_RectR){
            HTuple row,col,phi,length1,length2;
            SmallestRectangle2(mParam.createParam.modelROI,&row,&col,&phi,&length1,&length2);
            itemCreate = new ItemRectR(col.D(),row.D(),length1.D(),length2.D(),phi.D());
        } else if(mParam.createParam.roiType == DIT_Polygon){
            HTuple row,col;
            GetRegionPolygon(mParam.createParam.modelROI,5,&row,&col);
            int length = row.TupleLength().I();
            QList<QPointF> lstPoint;
            for(int i = 0; i < length; ++i){
                lstPoint << QPointF(col[i],row[i]);
            }
            itemCreate = new ItemPolygon(lstPoint);
        }else {
            return;
        }
        wgtRoiModelCreate->getView()->addItem(itemCreate);

        ItemBase* itemFind;
        if(mParam.findParam.roiType == DIT_RectR){
            HTuple row,col,phi,length1,length2;
            SmallestRectangle2(mParam.findParam.findROI,&row,&col,&phi,&length1,&length2);
            itemFind = new ItemRectR(col.D(),row.D(),length1.D(),length2.D(),phi.D());
        } else if(mParam.createParam.roiType == DIT_Polygon){
            HTuple row,col;
            GetRegionPolygon(mParam.findParam.findROI,5,&row,&col);
            int length = row.TupleLength().I();
            QList<QPointF> lstPoint;
            for(int i = 0; i < length; ++i){
                lstPoint << QPointF(col[i],row[i]);
            }
            itemFind = new ItemPolygon(lstPoint);
        }else {
            return;
        }
        wgtRoiModelCreate->getView()->addItem(itemFind);
    } catch (HException e) {
        qDebug() << "model match widget load par find";
    }
}

void HalconModelMatchWidget::closeEvent(QCloseEvent *e)
{
    emit sigParamChanged(mParam);
}

void HalconModelMatchWidget::setupUI()
{
    QHBoxLayout* hLayout = new QHBoxLayout();
    this->setLayout(hLayout);
    tabwgt = new QTabWidget();
    hLayout->addWidget(tabwgt);
    setupPageModelCreate();
    setupPageModelFind();
}

void HalconModelMatchWidget::setupPageModelCreate()
{
    wgtRoiModelCreate = new WidgetRoiDraw();
    wgtRoiModelCreate->setMode(RWM_ModelMatch);
    spboxNumLevels = new QSpinBox();
    spboxAngleStart = new QSpinBox();
    dspboxAngleStep = new QDoubleSpinBox();
    cbboxOptimization = new QComboBox();
    cbboxCreateShape = new QComboBox();
    cbboxMetric = new QComboBox();
    spboxContrastHigh = new QSpinBox();
    spboxContrastLow = new QSpinBox();
    spboxPieceSizeMin = new QSpinBox();
    spboxContrastMin = new QSpinBox();
    spboxCenterPosRow = new QSpinBox();
    spboxCenterPosCol = new QSpinBox();
    pbtnModelCreate = new QPushButton("创建模板");

    spboxNumLevels->setRange(1,10);
    spboxAngleStart->setRange(-180,180);
    spboxContrastHigh->setRange(0,255);
    spboxContrastLow->setRange(0,255);
    spboxCenterPosRow->setRange(-1,10000);
    spboxCenterPosCol->setRange(-1,10000);
    cbboxOptimization->addItems({"none", "point_reduction_low", "point_reduction_medium", "point_reduction_high"});
    cbboxCreateShape->addItems({"no_pregeneration", "pregeneration"});
    cbboxMetric->addItems({"use_polarity", "ignore_global_polarity", "ignore_local_polarity", "ignore_color_polarity"});

    int width = 200;
    spboxNumLevels->setFixedWidth(width);
    spboxAngleStart->setFixedWidth(width);
    dspboxAngleStep->setFixedWidth(width);
    cbboxOptimization->setFixedWidth(width);
    cbboxCreateShape->setFixedWidth(width);
    cbboxMetric->setFixedWidth(width);
    spboxContrastHigh->setFixedWidth(width);
    spboxContrastLow->setFixedWidth(width);
    spboxPieceSizeMin->setFixedWidth(width);
    spboxContrastMin->setFixedWidth(width);
    spboxCenterPosRow->setFixedWidth(width);
    spboxCenterPosCol->setFixedWidth(width);
    pbtnModelCreate->setFixedWidth(width);

    QHBoxLayout* hLayout = new QHBoxLayout();
    {
        hLayout->addWidget(wgtRoiModelCreate);
        {
            QVBoxLayout* vLayout = new QVBoxLayout();
            hLayout->addLayout(vLayout);
            {
                vLayout->addWidget(new QLabel("NumLevels"));
                vLayout->addWidget(spboxNumLevels);
                vLayout->addWidget(new QLabel("AngleStart"));
                vLayout->addWidget(spboxAngleStart);
                vLayout->addWidget(new QLabel("AngleStep"));
                vLayout->addWidget(dspboxAngleStep);
                vLayout->addWidget(new QLabel("Optimization"));
                vLayout->addWidget(cbboxOptimization);
                vLayout->addWidget(new QLabel("CreateShapePre"));
                vLayout->addWidget(cbboxCreateShape);
                vLayout->addWidget(new QLabel("Metric"));
                vLayout->addWidget(cbboxMetric);
                vLayout->addWidget(new QLabel("ContrastHigh"));
                vLayout->addWidget(spboxContrastHigh);
                vLayout->addWidget(new QLabel("ContrastLow"));
                vLayout->addWidget(spboxContrastLow);
                vLayout->addWidget(new QLabel("PieceSizeMin"));
                vLayout->addWidget(spboxPieceSizeMin);
                vLayout->addWidget(new QLabel("ContrastMin"));
                vLayout->addWidget(spboxContrastMin);
                vLayout->addWidget(new QLabel("CenterPosRow"));
                vLayout->addWidget(spboxCenterPosRow);
                vLayout->addWidget(new QLabel("CenterPosCol"));
                vLayout->addWidget(spboxCenterPosCol);
                vLayout->addWidget(pbtnModelCreate);
                vLayout->addStretch();
            }
        }
    }
    QWidget* wgt = new QWidget();
    wgt->setLayout(hLayout);
    tabwgt->addTab(wgt,"创建模板");
}

void HalconModelMatchWidget::setupPageModelFind()
{
    //findmodel
    wgtRoiModelFind = new WidgetRoiDraw();
    wgtRoiModelFind->setMode(RWM_ModelMatch);
    pbtnOpenImage = new QPushButton("打开图像");
    pbtnOpenFolder = new QPushButton("选择路径");
    pbtnOpenPre = new QPushButton("上一张");
    pbtnOpenNext = new QPushButton("下一张");

    dspboxMinScore = new QDoubleSpinBox();
    spboxNumToFind = new QSpinBox();
    dspboxMaxOverlap = new QDoubleSpinBox();
    cbboxSubPixel = new QComboBox();
    spboxNumLevelMin = new QSpinBox();
    dspboxGreedness = new QDoubleSpinBox();
    pbtnModelFind = new QPushButton("查找");

    dspboxMinScore->setRange(0, 1);
    dspboxMaxOverlap->setRange(0, 1);
    dspboxGreedness->setRange(0, 1);
    spboxNumLevelMin->setRange(1,5);
    cbboxSubPixel->addItems({"none", "interpolation", "least_squares", "least_squares_high", "least_squares_very_high"});

    int width = 150;
    dspboxMinScore->setFixedWidth(width);
    spboxNumToFind->setFixedWidth(width);
    dspboxMaxOverlap->setFixedWidth(width);
    cbboxSubPixel->setFixedWidth(width);
    spboxNumLevelMin->setFixedWidth(width);
    dspboxGreedness->setFixedWidth(width);
    pbtnModelFind->setFixedWidth(width);

    QHBoxLayout* hLayout0 = new QHBoxLayout();
    {
        QVBoxLayout* vLayout0 = new QVBoxLayout();
        hLayout0->addLayout(vLayout0);
        {
            vLayout0->addWidget(wgtRoiModelFind);
        }
        {
            QHBoxLayout* hLayout00 = new QHBoxLayout();
            vLayout0->addLayout(hLayout00);
            {
                hLayout00->addWidget(pbtnOpenImage);
                hLayout00->addWidget(pbtnOpenFolder);
                hLayout00->addWidget(pbtnOpenPre);
                hLayout00->addWidget(pbtnOpenNext);
                hLayout00->addStretch();
            }
        }
    }
    {
        QVBoxLayout* vLayout1 = new QVBoxLayout();
        hLayout0->addLayout(vLayout1);
        {
            vLayout1->addWidget(new QLabel("MinScore"));
            vLayout1->addWidget(dspboxMinScore);
            vLayout1->addWidget(new QLabel("NumToFind"));
            vLayout1->addWidget(spboxNumToFind);
            vLayout1->addWidget(new QLabel("MaxOverlap"));
            vLayout1->addWidget(dspboxMaxOverlap);
            vLayout1->addWidget(new QLabel("SubPixel"));
            vLayout1->addWidget(cbboxSubPixel);
            vLayout1->addWidget(new QLabel("NumLevelMin"));
            vLayout1->addWidget(spboxNumLevelMin);
            vLayout1->addWidget(new QLabel("Greedness"));
            vLayout1->addWidget(dspboxGreedness);
            vLayout1->addWidget(pbtnModelFind);
            vLayout1->addStretch();
        }
    }

    QWidget* wgt = new QWidget();
    wgt->setLayout(hLayout0);
    tabwgt->addTab(wgt,"查找模板");
}

void HalconModelMatchWidget::initUI()
{
    //createmodel
    spboxNumLevels->setValue(7);
    spboxAngleStart->setValue(-30);
    dspboxAngleStep->setValue(0.1);
    cbboxOptimization->setCurrentText("none");
    cbboxCreateShape->setCurrentText("no_pregeneration");
    cbboxMetric->setCurrentText("use_polarity");
    spboxContrastHigh->setValue(100);
    spboxContrastLow->setValue(20);
    spboxPieceSizeMin->setValue(5);
    spboxContrastMin->setValue(10);
    spboxCenterPosRow->setValue(-1);
    spboxCenterPosCol->setValue(-1);
    //findmodel
    dspboxMinScore->setValue(0.5);
    spboxNumToFind->setValue(1);
    dspboxMaxOverlap->setValue(0.7);
    cbboxSubPixel->setCurrentText("least_squares");
    spboxNumLevelMin->setValue(1);
    dspboxGreedness->setValue(0.75);
}

void HalconModelMatchWidget::initConnection()
{
    connect(pbtnModelCreate, &QPushButton::clicked, this, [&](){
        updateModelCreatePar();
        //训练模板
        HObject modelImage = ImageCommon::imageToHImage(mImg);
        HObject ho_Cross_M;
        HTuple modelMat, modelID;
        QtHalcon::createModel(modelImage, mParam.createParam.modelROI, &ho_Cross_M,
                              mParam.createParam,
                              &modelID, &modelMat);
        if(!(modelID.TupleLength()>0))return;
        mParam.findParam.modelID = modelID;
        mParam.findParam.modelMat = modelMat;
        wgtRoiModelCreate->getView()->clearDraw();
        QVector<QVector<QPointF>> xldList = QtHalcon::getListModelXld(modelID, modelMat);
        wgtRoiModelCreate->getView()->addXldList(xldList);

    });
    connect(pbtnModelFind, &QPushButton::clicked, this, [&](){
        updateModelFindPar();
        //训练模板
        HObject modelImage = ImageCommon::imageToHImage(mImg);
        //查找模板
        HObject ho_ModelAtNewPosition,ho_Cross;
        HTuple hv_Success,hv_MovementOfObject_Model_S,hv_Row,hv_Column,hv_Angle,hv_Score;
        QtHalcon::checkModel(modelImage, &ho_ModelAtNewPosition, &ho_Cross, mParam.findParam,
                             &hv_Success, &hv_MovementOfObject_Model_S, &hv_Row, &hv_Column,
                             &hv_Angle, &hv_Score);
        mParam.findParam.modelRow = hv_Row;
        mParam.findParam.modelCol = hv_Column;
        mParam.findParam.modelAngle = hv_Angle;
        wgtRoiModelFind->getView()->clearDraw();
        QVector<QVector<QPointF>> xldList = QtHalcon::getListXld(ho_ModelAtNewPosition);
        wgtRoiModelFind->getView()->addXldList(xldList);
    });
}
void HalconModelMatchWidget::updateModelCreatePar()
{
    mParam.createParam.modelROI = QtHalcon::tranItemToHobject(wgtRoiModelCreate->getItem());
    mParam.createParam.numLevels = spboxNumLevels->value();
    mParam.createParam.angleStart = spboxAngleStart->value();
    mParam.createParam.angleStep = dspboxAngleStep->value();
    mParam.createParam.angleExtent = abs(spboxAngleStart->value()) * 2;
    mParam.createParam.contrastMin = spboxContrastMin->value();
    mParam.createParam.centerPosRow = spboxCenterPosRow->value();
    mParam.createParam.centerPosCol = spboxCenterPosCol->value();
    mParam.createParam.metric = cbboxMetric->currentText().toStdString().data();

    HTuple constrast = HTuple();
    constrast[0] = spboxContrastLow->value();
    constrast[1] = spboxContrastHigh->value();
    constrast[2] = spboxPieceSizeMin->value();
    mParam.createParam.contrast = constrast;

    HTuple optimization = HTuple();
    optimization[0] = cbboxOptimization->currentText().toStdString().data();
    optimization[1] = cbboxCreateShape->currentText().toStdString().data();
    mParam.createParam.optimization = optimization;
}

void HalconModelMatchWidget::updateModelFindPar()
{
    //获取查找模板参数
    mParam.findParam.findROI = QtHalcon::tranItemToHobject(wgtRoiModelFind->getItem());
    mParam.findParam.angleStart = mParam.createParam.angleStart;
    mParam.findParam.angleExtent = mParam.createParam.angleExtent;
    mParam.findParam.numToFind = spboxNumToFind->value();
    mParam.findParam.minScore = dspboxMinScore->value();
    mParam.findParam.maxOverlap = dspboxMaxOverlap->value();
    mParam.findParam.subPixel = cbboxSubPixel->currentText().toStdString().data();
    mParam.findParam.greediness = dspboxGreedness->value();

    HTuple numlevel = HTuple();
    numlevel[0] = mParam.createParam.numLevels;
    numlevel[1] = spboxNumLevelMin->value();
    mParam.findParam.numLevels = numlevel;
}
